//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.ScientificWorkflow.ManagementStudioControls.RegistryManagerModule
{
    using System;
    using System.Collections.ObjectModel;
    using System.Windows;
    using Microsoft.Research.ScientificWorkflow.ManagementStudioModels;
    using Microsoft.Research.ScientificWorkflow.UIDesigner.WpfComposite;
    using Microsoft.Practices.Unity;
    using ManagementStudioServices.Interfaces;

    public abstract class RegistryManagerLeftPaneItemPresenterBase : IRegistryManagerLeftPaneItemPresenter
    {
        #region Private Members

        /// <summary>
        /// The unity container.
        /// </summary>
        private IUnityContainer container;

        /// <summary>
        /// Service for registry access.
        /// </summary>
        private IRegistryManagerService registryManagerService;

        #endregion Private Members

        /// <summary>
        /// Gets or sets the left pane tree items.
        /// </summary>
        /// <value>The left pane tree items.</value>
        public virtual ObservableCollection<BaseRegMgrModel> LeftPaneTreeItems { get; private set; }

        /// <summary>
        /// Flag to determine whether the presenter is currently selected.
        /// </summary>
        public virtual bool IsSelected { get; set; }

        /// <summary>
        /// Gets or sets the search view.
        /// </summary>
        /// <value>The search view.</value>
        public virtual UIElement SearchView { get; set; }

        /// <summary>
        /// Gets or sets the left pane view.
        /// </summary>
        /// <value>The left pane view.</value>
        public virtual UIElement LeftPaneView { get; set; }

        /// <summary>
        /// Gets or sets the left pane presener.
        /// </summary>
        /// <value>The left pane presener.</value>
        public virtual ILeftPaneControl LeftPanePresenter { get; set; }

        /// <summary>
        /// Gets or sets the item selected command.
        /// </summary>
        /// <value>The item selected command.</value>
        public virtual DelegateCommand<BaseRegMgrModel> ItemSelectedCommand { get; private set; }

        /// <summary>
        /// Gets the registry manager service.
        /// </summary>
        /// <value>The registry manager service.</value>
        public IRegistryManagerService RegistryManagerService { get { return this.registryManagerService; } }

        /// <summary>
        /// Gets or sets the root model.
        /// </summary>
        /// <value>The root model.</value>
        public abstract BaseRegMgrModel RootModel { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="RegistryManagerLeftPaneItemPresenterBase"/> class.
        /// </summary>
        /// <param name="container">The container.</param>
        /// <param name="service">The service.</param>
        public RegistryManagerLeftPaneItemPresenterBase(IUnityContainer container, IRegistryManagerService service)
        {
            this.container = container;
            this.registryManagerService = service;
            this.LeftPaneTreeItems = new ObservableCollection<BaseRegMgrModel>();
            this.ItemSelectedCommand = new DelegateCommand<BaseRegMgrModel>(this.ItemSelected);
        }

        /// <summary>
        /// Initializes this instance.
        /// </summary>
        public abstract void Initialize();

        /// <summary>
        /// Refreshes this instance.
        /// </summary>
        public virtual void Refresh(BaseRegMgrModel selectedModel)
        {
            this.Initialize();
            if (selectedModel != null)
            {
                selectedModel = selectedModel.GetModelById(selectedModel, this.LeftPaneTreeItems);
                if (selectedModel != null)
                {
                    this.ItemSelected(selectedModel);
                }
            }
        }
        
        private void ItemSelected(BaseRegMgrModel selectedModel)
        {
            if (selectedModel != null)
            {
                IRegistryManagerCenterPanePresenter centerPanePresenter = RegistryManagerPresenterFactory.FetchCenterPanePresenter(selectedModel.GetType());
                centerPanePresenter.UpdateCommand = new DelegateCommand<BaseRegMgrModel>(this.OnUpdateRequest);
                centerPanePresenter.RefreshCommand = new DelegateCommand<BaseRegMgrModel>(this.Refresh);
                centerPanePresenter.DeleteCommand = new DelegateCommand<BaseRegMgrModel>(this.OnDeleteRequest);
                centerPanePresenter.SelectRootCommand = new DelegateCommand<object>(p => this.OnSelectRoot());

                SaveStateHandler saveState = new SaveStateHandler(SaveStatus.Valid);
                (this.LeftPanePresenter as RegistryManagerLeftPanePresenter).ItemSelected.Execute(new object[] { centerPanePresenter, this, saveState });
                if (saveState.SaveOptionSelected == SaveStatus.Valid)
                {
                    centerPanePresenter.SelectedModel = selectedModel;
                    if (!selectedModel.IsSelected)
                    {
                        selectedModel = selectedModel.GetModelById(selectedModel, this.LeftPaneTreeItems);
                        selectedModel.IsSelected = true;
                    }
                }
                else if (saveState.SaveOptionSelected == SaveStatus.Invalid)
                {
                    if (selectedModel.IsSelected)
                    {
                        selectedModel = selectedModel.GetModelById(selectedModel, this.LeftPaneTreeItems);
                        selectedModel.IsSelected = false;
                    }
                }
            }
        }

        /// <summary>
        /// Called on a select root request.
        /// </summary>
        private void OnSelectRoot()
        {
            if (this.RootModel != null)
            {
                this.RootModel.IsSelected = false;
                this.RootModel.IsSelected = true;
            }
        }

        private void OnUpdateRequest(BaseRegMgrModel model)
        {
            if (model != null)
            {
                BaseRegMgrModel modelToSelect = model.GetModelById(model, this.LeftPaneTreeItems);
                if (modelToSelect != null)
                {
                    if (model.Parent != null)
                    {
                        BaseRegMgrModel newParentToSelect = null;
                        if (modelToSelect.Parent != null)
                        {
                            if (!modelToSelect.Parent.Id.Equals(model.Parent.Id))
                            {
                                newParentToSelect = model.Parent;
                            }
                        }
                        else
                        {
                            newParentToSelect = model.Parent;
                        }

                        if (newParentToSelect != null && !newParentToSelect.Id.Equals(Guid.Empty))
                        {
                            BaseRegMgrModel newParent = newParentToSelect.GetModelById(newParentToSelect, this.LeftPaneTreeItems);
                            BaseRegMgrModel oldParent = modelToSelect.Parent;
                            if (ActivityLeftPanePresenter.MoveModel(modelToSelect, oldParent, newParent))
                            {
                                modelToSelect.Parent = newParent;
                            }
                        }
                    }

                    modelToSelect.Update(model);
                }
                else
                {
                    if (model.Parent != null)
                    {
                        BaseRegMgrModel newParent = model.Parent.GetModelById(model.Parent, this.LeftPaneTreeItems);
                        ActivityLeftPanePresenter.MoveModel(model, null, newParent);
                    }
                }
            }
        }

        private void OnDeleteRequest(BaseRegMgrModel model)
        {
            if (model != null && model.Parent != null)
            {
                BaseRegMgrModel parentModel = model.Parent.GetModelById(model.Parent, this.LeftPaneTreeItems);
                if (parentModel != null)
                {
                    if (parentModel.Children.Contains(model))
                    {
                        parentModel.Children.Remove(model);
                    }

                    CategoryViewModel categoryModel = model as CategoryViewModel;
                    if (categoryModel != null)
                    {
                        this.Refresh(parentModel);
                    }
                }
            }
        }

        private static bool MoveModel(BaseRegMgrModel modelToMove, BaseRegMgrModel oldParent, BaseRegMgrModel newParent)
        {
            bool removeSuccess = false;
            if (modelToMove != null && newParent != null)
            {
                removeSuccess = true;
                if (oldParent != null)
                {
                    if (oldParent.Children.Contains(modelToMove))
                    {
                        removeSuccess = oldParent.Children.Remove(modelToMove);
                    }
                }

                if (removeSuccess)
                {
                    newParent.Children.Add(modelToMove);
                    modelToMove.Parent = newParent;
                }
            }

            return removeSuccess;
        }
    }
}
